package grpc

import (
	"context"
	authpb "e-commerce/services/auth-service/api/pb"
	orderpb "e-commerce/services/order-service/api/pb"
	"e-commerce/services/order-service/internal/service"
	"os"
	"strings"

	"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/credentials/insecure"
	"google.golang.org/grpc/metadata"
	"google.golang.org/grpc/status"
	yaml "sigs.k8s.io/yaml/goyaml.v3"
)

type OrderService struct {
	orderpb.UnimplementedOrderServiceServer
	Service    *service.OrderService
	AuthClient *authClient
}

type authClient struct {
	client authpb.AuthServiceClient
	conn   *grpc.ClientConn
}

type Config struct {
	AuthService auth_service `yaml:"auth_service"`
}

type auth_service struct {
	Addr string `yaml:"addr"`
}

func NewAuthClient(configPath string) (*authClient, error) {
	yamlFile, err := os.ReadFile(configPath)
	if err != nil {
		return nil, err
	}
	var config Config
	err = yaml.Unmarshal(yamlFile, &config)
	if err != nil {
		return nil, err
	}
	conn, err := grpc.NewClient(
		config.AuthService.Addr,
		grpc.WithTransportCredentials(insecure.NewCredentials()),
		//添加OpenTelemetry遥测
		grpc.WithStatsHandler(otelgrpc.NewClientHandler()),
	)
	if err != nil {
		return nil, err
	}
	return &authClient{
		client: authpb.NewAuthServiceClient(conn),
		conn:   conn,
	}, nil
}

func NewOrderService(configpath string) (*OrderService, error) {
	service := service.NewOrderService(configpath)
	authClient, err := NewAuthClient(configpath)
	if err != nil {
		return nil, err
	}
	return &OrderService{
		Service:    service,
		AuthClient: authClient,
	}, nil
}

func (s *OrderService) CreateOrder(ctx context.Context, req *orderpb.CreateOrderRequest) (*orderpb.CreateOrderResponse, error) {
	userID, ok := ctx.Value(userIDKey).(int32)
	if !ok {
		return nil, status.Error(codes.Unauthenticated, "user_id is required")
	}
	req.Order.UserId = userID
	orderID, err := s.Service.CreateOrder(req.Order)
	if err != nil {
		return nil, err
	}
	return &orderpb.CreateOrderResponse{OrderId: orderID}, nil
}

func (s *OrderService) GetOrder(ctx context.Context, req *orderpb.GetOrderRequest) (*orderpb.GetOrderResponse, error) {
	order, err := s.Service.GetOrder(req.OrderId)
	if err != nil {
		return nil, err
	}
	return &orderpb.GetOrderResponse{Order: order}, nil
}

func (s *OrderService) CancelOrder(ctx context.Context, req *orderpb.CancelOrderRequest) (*orderpb.CancelOrderResponse, error) {
	err := s.Service.CancelOrder(req.OrderId)
	if err != nil {
		return &orderpb.CancelOrderResponse{Success: false}, err
	}
	return &orderpb.CancelOrderResponse{Success: true}, nil
}

func (s *OrderService) MarkOrderPaid(ctx context.Context, req *orderpb.MarkOrderPaidRequest) (*orderpb.MarkOrderPaidResponse, error) {
	err := s.Service.MarkOrderPaid(req.OrderId, req.Success)
	if err != nil {
		return &orderpb.MarkOrderPaidResponse{Success: false}, err
	}
	return &orderpb.MarkOrderPaidResponse{Success: true}, nil
}

type contextKey string

const (
	userIDKey contextKey = "user_id"
	roleKey   contextKey = "role"
)

func (s *OrderService) AuthMiddleware(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
	//服务端添加了otelgrpc.NewServerHandler()，所以不需要创建子span
	//创建子span
	// ctx, authSpan := otel.Tracer("auth-grpc-middleware").Start(
	// 	ctx,
	// 	"auth-grpc-middleware",
	// 	trace.WithSpanKind(trace.SpanKindInternal),
	// )

	// defer authSpan.End()

	// defer s.AuthClient.Close()
	//从metadata中获取token
	md, ok := metadata.FromIncomingContext(ctx)
	if !ok {
		return nil, status.Error(codes.Unauthenticated, "metadata is required")
	}
	authHeaders := md.Get("authorization")
	if len(authHeaders) == 0 {
		return nil, status.Error(codes.Unauthenticated, "authorization header is required")
	}
	authHeader := authHeaders[0]
	const prefix = "Bearer "
	if !strings.HasPrefix(authHeader, prefix) {
		return nil, status.Error(codes.Unauthenticated, "invalid authorization header")
	}
	token := strings.TrimPrefix(authHeader, prefix)
	// 调用 auth-service 验证 token
	validateResp, err := s.AuthClient.client.ValidateToken(ctx, &authpb.ValidateTokenRequest{
		Token: token,
	})
	if err != nil {
		return nil, status.Error(codes.Unauthenticated, err.Error())
	}

	if !validateResp.Valid {
		return nil, status.Error(codes.Unauthenticated, "invalid token")
	}

	// 将用户信息添加到上下文
	newCtx := context.WithValue(ctx, userIDKey, validateResp.UserId)
	newCtx = context.WithValue(newCtx, roleKey, validateResp.Role)

	// 调用实际的处理函数
	return handler(newCtx, req)
}
